#!/usr/bin/env python
# coding: utf-8
import os
import sys
import re
import shutil
import zipfile
import pdb

# path=os.getcwd()
# if path not in sys.path:
#     sys.path.append(path)
# rootpath = os.path.dirname(path)
# if rootpath not in sys.path:
#     sys.path.append(rootpath)
# print(sys.path)  
from onshs.tnxxxcfg_basecase import *

# pdb.set_trace()

class TestCase (TnxxxCfg_BaseCase) :
    """
    TestCase
    """
    OPTIONS = [        
        {
           'opt' : '--ip',
           'dest': 'ip',
           'metavar' : 'IP',
           'help' : 'the ip of ne',
           'required' : False,
           'default' : "10.15.1.32"
        },
        {
           'opt' : '--log',
           'dest': 'log',
           'metavar' : 'log',
           'help' : 'need collect log or not',
           'required' : False,
           'default' : "disable"
        },
    ]

    list_lsp_oam = []
    list_aps_id = []
    
    #分析每个单板类型支持的命令文件,保存到card_config_dic中.
    def parse_card_config(self):
        # 检查card_config是否存在        
        card_config_file = self.work_path + r'/card_config.txt'
            
        if not os.path.isfile(card_config_file):
            print("file ：'card_config.txt' is not exist")
            return False
        
        # 读取card_config中的配置
        self.card_config_dic = {}
        card_config_list = open(card_config_file)
        for line in card_config_list.readlines():
            m = re.match(r'^\s*([\w\d]+)\s*:\s*([\w\d]+_\d+\s*(?:,\s*[\w\d]+_\d+\s*)*)$',line)
            if m is None:
                continue
            self.card_config_dic[m.group(1)] = [s.strip() for s in m.group(2).split(',')]
        card_config_list.close()
        # 检查对应的cmd文件是否存在
        for key in self.card_config_dic:
            # print key
            for file_name in self.card_config_dic[key]:
                file_name += '.txt'
                if not os.path.isfile(self.work_path + r'/cmd/' + file_name):
                    print("file : '%s' is not exist"%(file_name))
                    return False
        return True
    
    #分析每个单板类型支持的命令文件,保存到card_config_dic中.
    def parse_log_config(self):
        # 检查card_config是否存在        
        log_config_file = self.work_path + r'/log_config.txt'
            
        if not os.path.isfile(log_config_file):
            print("file ：'log_config.txt' is not exist")
            return False
        
        # 读取log_config中的配置
        self.log_config_list = []
        log_list = open(log_config_file)
        for line in log_list.readlines():
            if re.match(r'^\s*$', line) is not None : continue # 忽略空白行
            if re.match(r'^\s*#', line) is not None : continue # 忽略注释行
            self.log_config_list.append(line)
        log_list.close()
        # print self.log_config_list

        return True
    
    #以node为关键字，把信息保存到info_dic[node]中。
    def info_show(self, node, info):
        # if not self.info_dic.has_key(node):
        if node not in self.info_dic:
            self.info_dic[node] = ""
        self.info_dic[node] += info + '\n'
        print(info)
        return True

    def info_file_clear(self):
        if os.path.exists(self.work_path+r'/collect'):
            shutil.rmtree(self.work_path+r'\\collect')
        if os.path.exists(self.work_path+r'/collect.zip'):
            os.remove(self.work_path+r'\\collect.zip')
        return True
            
    def info_file_save(self, ip):
        path = self.work_path+r'/collect/'+ip
        if not os.path.isdir(path):
            os.makedirs(path)
        for node in self.info_dic:
            open(path+r'/'+node+'.txt','w').write(self.info_dic[node])
        return True
    
    def get_file_list(self, sub_dir, file_list):
        path = self.work_path+r'/'+sub_dir
        name_list = os.listdir(path)
        for name in name_list:
            if name is '.' or name is '..' : continue
            if os.path.isfile(path+name):
                file_list.append([sub_dir,name])
            elif os.path.isdir(path+name):
                self.get_file_list(sub_dir+name+r'/', file_list)
        return True
                
    def info_file_zip(self):
        file_list = []
        self.get_file_list(r'collect/', file_list)
        zf = zipfile.ZipFile(self.work_path+r'/collect.zip', 'w')
        for sub_dir,file in file_list:
            zf.write(self.work_path+r"/"+sub_dir+file,sub_dir+file)
        zf.close()
        return True
                    
        
    def get_phycard(self, ip):
        phycard_list = []
        if not self.tnxxx.send("configure terminal", ip=ip, slot=0, port=CLI_PORT):
            self.info_show('system', "***info_collect:connect failed!!!***")
            return phycard_list
        rtn_str = self.tnxxx.send_rtn_str("show card", ip=ip, slot=0, port=CLI_PORT)
        if not self.tnxxx.send("exit", ip=ip, slot=0, port=CLI_PORT):
            self.info_show('system', "connect failed!!!")
            return phycard_list
        self.info_show('system', rtn_str+'\n'+'#'*80)
        phycard_list = re.findall(r"slot:\s+(\d+)\s+stat:\s+\w+\s+Card:\s+(\w+)\s+", rtn_str, re.I)
        # print(phycard_list)
        for card in phycard_list:
            print(card)
        return phycard_list
    
    def check_card_task(self, ip, slot, node_h):
        # 检查网元上的任务，如果有任务挂起，就打印出该任务的调用栈
        rtn_str = self.tnxxx.send_rtn_str("i", ip=ip, slot=slot, port=DEV_PORT)
        self.info_show('system', rtn_str+'\n'+'#'*80)
        e_tid_list = re.findall(r'\s+([\da-f]+)\s+\d+\s+(?:SUSPEND|\+S|STOP|ST\+)',rtn_str)
        for e_tid in e_tid_list:
            rtn_str = self.tnxxx.send_rtn_str("tt 0x%s"%(e_tid), ip=ip, slot=slot, port=DEV_PORT)
            self.info_show('system', rtn_str+'\n'+'#'*80)        
        return True
    
    # 获取网元单板的所有log.
    def collect_information_slot_log(self, ip, slot, node_h):
        start_index = 0
        log_count = 1000
        search_key = '999'
        node = node_h+'log'
        while True:
            rtn_str = self.tnxxx.send_rtn_str(r'$.nsp.log.0.show_rmem_logs "",%s,%s,UNORMAL' %(start_index, log_count), ip, slot, port=MTN_PORT)
            self.info_show(node, rtn_str+'\n'+'#'*80)
            if [] == re.findall(search_key, rtn_str):
                break;
            start_index += 1000
            time.sleep(3)
            
            
        start_index = 0
        while True:
            rtn_str = self.tnxxx.send_rtn_str(r'$.nsp.log.0.show_rmem_logs "",%s,%s,NORMAL' %(start_index, log_count), ip, slot, port=MTN_PORT)
            self.info_show(node, rtn_str+'\n'+'#'*80)
            if [] == re.findall(search_key, rtn_str):
                break;
            start_index += 1000
            time.sleep(3)
            
        return True
    
    #根据日志点对收集到的log文件进行排序.
    def sort_information(self, ip):
        phycard_list = self.get_phycard(ip)
        for phycard in phycard_list:
            slot = int(phycard[0])
            card_name = phycard[1]
            if card_name not in list(self.card_config_dic.keys()) :
                continue
            node_h = "%d_%s_"%(slot, card_name)
            node = node_h+'log'
            
            for log_key in self.log_config_list:           
                log_file = open(self.work_path+r'/collect/'+ip+r'/'+node+'.txt')            
                log_file_sorted = open(self.work_path+r'/collect/'+ip+r'/'+node+'_sorted.txt','a+')
            
                #取log_key[0:4]的主要目的是切除\n.
                log_file_sorted.write(r'$.nsp.log.0.show_rmem_logs %s,0,ALL,NORMAL and UNORMAL' %(log_key[0:4]))
                log_file_sorted.write('\n'+'#'*80+'\n')
                for each_line in log_file:                    
                    if [] != re.findall(log_key[0:4], each_line):                                             
                        log_file_sorted.write(each_line+'\n')  
            
                log_file.close()
                log_file_sorted.close()
                
        return True
            
    def collect_information(self, ip) :
        # 收集各种带CPU的板的信息
        phycard_list = self.get_phycard(ip)
        for phycard in phycard_list:
            slot = int(phycard[0])
            card_name = phycard[1]
            # print slot,card_name            

            if card_name not in list(self.card_config_dic.keys()) :
                continue
            node_h = "%d_%s_"%(slot, card_name)
            self.check_card_task(ip, slot, node_h)            
            self.collect_information_slot_log(ip, slot, node_h)
            # continue

            for cmd_file in self.card_config_dic[card_name] :
                m = re.match(r'[\w\d]+_(\d+)', cmd_file)
                port = int(m.group(1))
                node = node_h+str(port)                
                cmd_count = 0
                cmd_list = open(self.work_path+r'/cmd/'+cmd_file+".txt", encoding='utf-8')
                for line in cmd_list:
                    if re.match(r'^\s*$', line) is not None : continue # 忽略空白行
                    if re.match(r'^\s*#', line) is not None : continue # 忽略注释行
                    line = re.sub('SLOT_NO', str(slot),line) #用具体槽位号替代SLOT_NO.
                    rtn_str = self.tnxxx.send_rtn_str(line, ip=ip, slot=slot, port=port)
                    self.info_show(node, rtn_str+'\n'+'#'*80)
                    cmd_count += 1
                cmd_list.close()
                self.info_show(node, '-'*80+'\nslot %d %s excute %d commands\n'%(slot,card_name,cmd_count)+'-'*80)
        return True

    def get_pre_define(self, ip) :
       # get lsp with oam
       rtn_str = self.tnxxx.send_rtn_str("$.dbgcli.0.RawSql \"cfg\",\"select LspId from MplsOam\"", ip=ip, slot=0, port=MTN_PORT)
       self.list_lsp_oam = re.findall(r'lspid=([0-9]+)', rtn_str)
       print(len(self.list_lsp_oam))

       # get aps id list
       rtn_str = self.tnxxx.send_rtn_str("$.dbgcli.0.RawSql \"cfg\",\"select ApsId from MplsApsCfg\"", ip=ip, slot=0, port=MTN_PORT)
       self.list_aps_id = re.findall(r'apsid=([0-9]+)', rtn_str)
       print(len(self.list_aps_id))
        
    def _execute(self):
        # self.work_path = os.path.dirname(os.path.realpath(__file__))
        self.work_path = os.getcwd()
        # 删除之前的收集的信息
        self.info_file_clear()
        # 参数分析和检查
        ip_list = self.options.ip.split(',')
        for ip in ip_list:
            if None == re.match(r'^(\d{1,3}.){3}\d{1,3}$',ip):  # 检查ip地址是否是A.B.C.D的格式
                print("param '--ip %s' error"%(self.options.ip))
                return False
        # 解析card_config文件        
        if not self.parse_card_config() : return False
        # 解析log_config文件        
        if not self.parse_log_config() : return False   
        # 收集每个网元的信息
        for ip in ip_list:            
            #self.get_pre_define(ip)
            self.info_dic = {}
            print('#'*80)
            self.info_show('system', "##### collect ne:%s information begin #####\n"%(ip))            
            self.collect_information(ip)
            self.info_show('system', "\n##### collect ne:%s information end #####"%(ip))
            #pdb.set_trace()
            self.info_file_save(ip)
            # self.sort_information(ip)
        # 压缩文件
        self.info_file_zip()
        print("*******************over************************")
        return True       

if __name__ == "__main__" :
    case = TestCase()
    case.execute(False)
    #os.system("pause")
